package com.iwhalecloud.bss.kite.cucc.service.batch;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.iwhalecloud.bss.kite.client.dto.DataResult;
import com.iwhalecloud.bss.kite.client.dto.cust.CustDTO;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.util.FunctionWrapper;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteMapUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.common.util.TransactionUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.batch.IBatchAcceptAdjustmentService;
import com.iwhalecloud.bss.kite.cucc.client.api.batch.IBatchAcceptService;
import com.iwhalecloud.bss.kite.cucc.client.api.goods.IGoodsPriceFactorService;
import com.iwhalecloud.bss.kite.cucc.client.api.reception.ICustReceptionService;
import com.iwhalecloud.bss.kite.cucc.client.api.scene.ISceneCommitService;
import com.iwhalecloud.bss.kite.cucc.client.api.shoppingcart.operate.ICuccOperateShoppingCartService;
import com.iwhalecloud.bss.kite.cucc.client.dto.batch.KiteBatchAccept;
import com.iwhalecloud.bss.kite.cucc.client.dto.batch.KiteBatchAcceptDetail;
import com.iwhalecloud.bss.kite.cucc.client.dto.batch.KiteBatchAcceptDetailDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.cust.CuccContextCustDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.scene.CuccCustInfoDetailDTO;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalKeyConsts;
import com.iwhalecloud.bss.kite.cucc.common.util.KiteAssert;
import com.iwhalecloud.bss.kite.cucc.dataservice.mapper.batch.KiteBatchAcceptDetailMapper;
import com.iwhalecloud.bss.kite.cucc.dataservice.mapper.batch.KiteBatchAcceptMapper;
import com.iwhalecloud.bss.kite.cucc.manager.inst.CuccKiteOfferInstAcct;
import com.iwhalecloud.bss.kite.cucc.manager.scene.service.operate.LocalOperateOfferInstAcctRelService;
import com.iwhalecloud.bss.kite.cucc.manager.scene.service.operate.LocalOperateOfferInstDiscountService;
import com.iwhalecloud.bss.kite.cucc.service.batch.enums.BatchAcceptStatusEnum;
import com.iwhalecloud.bss.kite.cucc.service.job.collectiongroup.StatusConst;
import com.iwhalecloud.bss.kite.cucc.service.pos.handler.CuccPosServiceUtils;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.cache.DcSystemParamCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferDetailCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdFeeCache;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Offer;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.OfferDetail;
import com.iwhalecloud.bss.kite.dataservice.util.GeneralSwitchUtils;
import com.iwhalecloud.bss.kite.dataservice.util.IdUtils;
import com.iwhalecloud.bss.kite.event.offer.InitMainOfferEvent;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQueryInstTemplateService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.enums.RelType;
import com.iwhalecloud.bss.kite.manager.inst.KiteAttr;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstContract;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstDiscount;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteSceneInst;
import com.iwhalecloud.bss.kite.manager.util.KiteTransactionUtils;
import com.iwhalecloud.bss.kite.service.context.ServiceContext;
import com.iwhalecloud.bss.kite.service.inf.accept.kitexchange.handler.AcceptScalpelUtil;
import com.iwhalecloud.bss.kite.service.scene.bo.OperateSceneBO;
import com.iwhalecloud.bss.kite.service.scene.bo.OperateSceneOfferInstBO;
import com.ztesoft.bss.common.bo.LoginInfo;
import com.ztesoft.bss.common.util.ContextUtil;
import com.ztesoft.bss.common.util.SpringUtil;
import com.ztesoft.zsmart.core.log.ZSmartLogger;

import lombok.RequiredArgsConstructor;
import tk.mybatis.mapper.entity.Example;

/**
 * @author : xie.zhengjun
 * @className : BatchAcceptAdjustmentService
 * @description : Happy Children's Day
 * @date : 2021/6/1 15:59
 */
@Service
@RequiredArgsConstructor
public class BatchAcceptAdjustmentService implements IBatchAcceptAdjustmentService {
    private static final ZSmartLogger LOGGER = ZSmartLogger.getLogger(BatchAcceptAdjustmentService.class);

    private final IQuerySceneInstService querySceneInstService;

    private final IOperateSceneInstService operateSceneInstService;

    private final IQueryInstTemplateService queryInstTemplateService;

    private final OperateSceneOfferInstBO operateSceneOfferInstBO;

    private final ApplicationContext applicationContext;

    private final KiteBatchAcceptDetailMapper kiteBatchAcceptDetailMapper;

    private final KiteBatchAcceptMapper kiteBatchAcceptMapper;

    private final LocalOperateOfferInstDiscountService operateOfferInstDiscountService;

    private final IBatchAcceptService batchAcceptService;

    private final LocalOperateOfferInstAcctRelService operateOfferInstAcctRelService;

    private final ICuccOperateShoppingCartService operateShoppingCartService;

    private final LocalBatchAcceptBO localBatchAcceptBO;

    private final IGoodsPriceFactorService goodsPriceFactorService;

    private final OperateSceneBO operateSceneBO;

    // 创建执行线程类集合
    ExecutorService executorService = null;

    public String getTemplateId(String offerId) {
        // TODO: 支持不同销售品配置不同的模板？
        return "400";
    }

//    @PostConstruct
//    public void initExecutorService() {
//        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("instantiate-thread-pool-%d")
//            .build();
//        executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 6,
//            Runtime.getRuntime().availableProcessors() + 6, 5000L, TimeUnit.MILLISECONDS,
//            new LinkedBlockingQueue<>(300), threadFactory);
//    }
//
//    @PreDestroy
//    public void desExecutorService() {
//        if (Objects.nonNull(executorService)) {
//            executorService.shutdown();
//        }
//    }

    /**
     * 将导入记录实例化
     *
     * @param sceneInstId           场景实例标识
     * @param kiteBatchAcceptDetail kiteBatchAcceptDetail记录
     * @return 修改页面的templateId
     */
    @Override public String instantiate(String sceneInstId, KiteBatchAcceptDetail kiteBatchAcceptDetail,
        CuccContextCustDTO contextCust, CustDTO custDTO) {
        KiteAssert.notNull(kiteBatchAcceptDetail, ErrorConsts.BUSI_COMMON_ERROR, "该记录不存在");
        KiteSceneInst sceneInst = null;
        if (Objects.nonNull(contextCust)) {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
        }
        else {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        }
        String provinceNbr = sceneInst.getProvinceNbr();
        String custId = sceneInst.getCustId();
        KiteOfferInst rootOfferInst = querySceneInstService.getOfferInst(custId, sceneInst.getRootInstId());
        String rootOfferInstId = rootOfferInst.getOfferInstId();
        String offerId = rootOfferInst.getOfferId();

        String offerInstId;
        if (Objects.nonNull(kiteBatchAcceptDetail.getOfferInstId())) {
            // 如果offerInstId在表中存在说明已经实例化过
            offerInstId = kiteBatchAcceptDetail.getOfferInstId().toString();
        }
        else {
            // 增加销售品实例
            ServiceContext.setIsBatchAccept(Boolean.TRUE);
            offerInstId = localBatchAcceptBO.addOfferInst(sceneInstId, sceneInst, provinceNbr, custId, offerId);
            ServiceContext.setCurOfferInstId(offerInstId);
            List<KiteProdInst> kiteProdInsts = querySceneInstService.listProdInstsFromOfferInst(custId, offerInstId);
//            setDefaultValue(kiteProdInsts.get(0), sceneInstId);
            operateSceneBO.executeBatchAcceptAttrAfter(custId, sceneInst, custDTO, kiteProdInsts.get(0));
            // 设置合同信息
            setContract(sceneInstId, custId, rootOfferInstId, offerId, offerInstId);
            // 设置折扣信息
            setDiscount(sceneInstId, custId, rootOfferInstId, offerInstId);
            // 设置付费关系
            setAccount(sceneInstId, custId, rootOfferInstId, offerId, offerInstId);
            // 设置可选包
            setAdditionalOfferInst(sceneInstId, custId, rootOfferInstId, offerInstId);
            // 设置销售品属性
            setOfferAttr(sceneInstId, custId, rootOfferInst, offerInstId);
            // 设置产品属性
            localBatchAcceptBO.setProdAttr(sceneInstId,
                Objects.requireNonNull(JSONObject.parseArray(kiteBatchAcceptDetail.getAttrJson(), KiteAttr.class)),
                custId, offerInstId, contextCust);
//            localBatchAcceptBO.setProdAttrUserInfo(sceneInstId, sceneInst.getCustId(),
//                sceneInst.getRootInstId(), contextCust);
            // 重新设置kiteAttr.instId
            List<KiteProdInst> newKiteProdInsts = querySceneInstService.listProdInstsFromOfferInst(custId, offerInstId);
            for (KiteProdInst kiteProdInst : newKiteProdInsts) {
                operateSceneInstService
                    .replaceAttrs(sceneInstId, kiteProdInst.getInstType(), kiteProdInst.getProdInstId(),
                        kiteProdInst.listAttrs());
            }
            // 设置完属性后，调资费计价接口
            setBatchAdditionalPrice(sceneInstId, custId, offerId, offerInstId);
        }
        System.out.println(offerInstId);
        operateSceneInstService.putExtParameter(sceneInstId, "curOfferInstId", offerInstId);
        return offerInstId;
    }

    public String instantiate2(String sceneInstId, KiteBatchAcceptDetail kiteBatchAcceptDetail,
                              CuccContextCustDTO contextCust, CustDTO custDTO) {
        KiteAssert.notNull(kiteBatchAcceptDetail, ErrorConsts.BUSI_COMMON_ERROR, "该记录不存在");
        KiteSceneInst sceneInst = null;
        if (Objects.nonNull(contextCust)) {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
        }
        else {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        }
        String provinceNbr = sceneInst.getProvinceNbr();
        String custId = sceneInst.getCustId();
        KiteOfferInst rootOfferInst = querySceneInstService.getOfferInst(custId, sceneInst.getRootInstId());
//        String rootOfferInstId = rootOfferInst.getOfferInstId();
        String offerId = rootOfferInst.getOfferId();

        String offerInstId;
        if (Objects.nonNull(kiteBatchAcceptDetail.getOfferInstId())
                    && Objects.nonNull(this.querySceneInstService.getKiteInst(custId, InstType.MAIN_OFFER_INST, kiteBatchAcceptDetail.getOfferInstId().toString()))) {
            // 如果offerInstId在表中存在说明已经实例化过
            offerInstId = kiteBatchAcceptDetail.getOfferInstId().toString();
        }
        else {
            // 增加销售品实例
            ServiceContext.setIsBatchAccept(Boolean.TRUE);
            offerInstId = localBatchAcceptBO.addOfferInst(sceneInstId, sceneInst, provinceNbr, custId, offerId);
        }
        System.out.println(offerInstId);

        return offerInstId;
    }

    /**
     * 设置默认值
     * @param kiteProdInst
     */
    private void setDefaultValue(KiteProdInst kiteProdInst, String sceneInstId) {
        List<KiteAttr> kiteAttrs = kiteProdInst.listAttrs();
        kiteAttrs.forEach(kiteAttr -> {
            if (KiteStringUtils.isNotEmpty(kiteAttr.getDefaultValue()) && KiteStringUtils.isEmpty(kiteAttr.getValue())) {
                kiteAttr.setValue(kiteAttr.getDefaultValue());
            }
        });
        operateSceneInstService.setAttrs(sceneInstId, kiteProdInst.getInstType(), kiteProdInst.getProdInstId(), kiteAttrs);
    }

    private CustDTO packageCustDTO(CuccContextCustDTO contextCust) {
        CustDTO custDTO = KiteBeanUtils.transform(contextCust, CustDTO.class);
        custDTO.setLanId(contextCust.getCityCode());
        custDTO.setRegionId(contextCust.getBcityCode());
        custDTO.setCustType(contextCust.getCustClassType());
        custDTO.setCertiType(contextCust.getCertiTypeCode());
        custDTO.setCertiNumber(contextCust.getCertiCode());
        return custDTO;
    }

    private void setOfferAttr(String sceneInstId, String custId, KiteOfferInst rootOfferInst, String offerInstId) {
        String saleGoodsCode = rootOfferInst.getAttrValue("saleGoodsCode");
        String saleGoodsName = rootOfferInst.getAttrValue("saleGoodsName");
        KiteOfferInst offerInst = querySceneInstService.getOfferInst(custId, offerInstId);
        if (KiteStringUtils.isEmpty(offerInst.getAttrValue("saleGoodsCode"))) {
            CuccPosServiceUtils.setExtParamValue(offerInst, sceneInstId, "saleGoodsCode", saleGoodsCode);
        }
        if (KiteStringUtils.isEmpty(offerInst.getAttrValue("saleGoodsName"))) {
            CuccPosServiceUtils.setExtParamValue(offerInst, sceneInstId, "saleGoodsName", saleGoodsName);
        }
        this.operateSceneInstService.addInst(sceneInstId, offerInst);
    }

    private String addOfferInst(String sceneInstId, KiteSceneInst sceneInst, String provinceNbr, String custId,
        String offerId) {
        KiteOfferInst offerInst = queryInstTemplateService.getOfferInst(offerId, provinceNbr);
        // 判断实例模版是否存在
        if (offerInst == null) {
            offerInst = operateSceneOfferInstBO
                .initKiteOfferInst(offerId, custId, InstType.MAIN_OFFER_INST, provinceNbr);
        }
        AcceptScalpelUtil.replaceInstId(offerInst, null);
        offerInst.setActionType(ActionType.A);
        String offerInstId = operateSceneInstService.addMainOfferInst(sceneInstId, offerInst);

        // 获取明细以发布新增销售品实例事件
        List<String> offerDetailIds = new ArrayList<>();
        List<OfferDetail> offerDetails = OfferDetailCache.get(offerId);
        if (KiteListUtils.isNotEmpty(offerDetails)) {
            offerDetailIds = offerDetails.stream().map(OfferDetail::getDetailId).collect(Collectors.toList());
        }


        InitMainOfferEvent initMainOfferEvent = new InitMainOfferEvent(this, custId, sceneInst.getStaffId());
        initMainOfferEvent.setOfferId(offerId);
        initMainOfferEvent.setParentInstId(offerInstId);
        initMainOfferEvent.setSceneInstId(sceneInstId);
        initMainOfferEvent.setDetailIds(offerDetailIds);
        initMainOfferEvent.setBatchAccept(ServiceContext.getIsBatchAccept());
        applicationContext.publishEvent(initMainOfferEvent);

        return offerInstId;
    }

    private void setAdditionalOfferInst(String sceneInstId, String custId, String rootOfferInstId, String offerInstId) {
        List<KiteOfferInst> rootAdditionalOfferInsts = querySceneInstService
            .listAdditionalOfferInstsFromOfferInst(custId, rootOfferInstId);
        for (KiteOfferInst rootAdditionalOfferInst : rootAdditionalOfferInsts) {
            KiteOfferInst additionalOfferInst = KiteBeanUtils.transform(rootAdditionalOfferInst, KiteOfferInst.class);
            additionalOfferInst.setOfferInstId(null);
//            AcceptScalpelUtil.replaceInstId(additionalOfferInst, offerInstId);
            operateSceneInstService.addAdditionalOfferInstToOfferInst(sceneInstId, additionalOfferInst, offerInstId,
                RelType.OFFER_REL_TYPE_100000, ActionType.A);
        }
    }

    private void setAccount(String sceneInstId, String custId, String rootOfferInstId, String offerId,
        String offerInstId) {
        List<CuccKiteOfferInstAcct> rootKiteOfferInstAccts = operateOfferInstAcctRelService
            .listOfferInstAccts(custId, rootOfferInstId);
        if (KiteListUtils.isNotEmpty(rootKiteOfferInstAccts)) {
            List<CuccKiteOfferInstAcct> kiteOfferInstAccts =
                KiteBeanUtils.copyPropsForList(rootKiteOfferInstAccts, CuccKiteOfferInstAcct.class);
            for (CuccKiteOfferInstAcct kiteOfferInstAcct : kiteOfferInstAccts) {
                kiteOfferInstAcct.setOfferInstId(offerInstId);
                kiteOfferInstAcct.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));

                operateSceneInstService
                    .addOfferInstAcct(sceneInstId, kiteOfferInstAcct, offerInstId, RelType.OFFER_OBJ_REL_TYPE_170000,
                        ActionType.A, KeyConsts.OFFER_ACCOUNT_ROLE, offerId);
            }
        }
    }

    private void setDiscount(String sceneInstId, String custId, String rootOfferInstId, String offerInstId) {
        List<KiteOfferInstDiscount> rootOfferInstDiscounts = operateOfferInstDiscountService
            .listOfferInstDiscounts(sceneInstId, custId, rootOfferInstId);
        if (KiteListUtils.isNotEmpty(rootOfferInstDiscounts)) {
            List<KiteOfferInstDiscount> kiteOfferInstDiscounts = rootOfferInstDiscounts.stream()
                .map(rootOfferInstDiscount -> {
                    KiteOfferInstDiscount kiteOfferInstDiscount = KiteBeanUtils
                        .transform(rootOfferInstDiscount, KiteOfferInstDiscount.class);
                    kiteOfferInstDiscount.setOfferInstId(offerInstId);
                    return kiteOfferInstDiscount;
                }).collect(Collectors.toList());
            operateOfferInstDiscountService
                .entryOfferInstDiscount(sceneInstId, custId, offerInstId, JSON.toJSONString(kiteOfferInstDiscounts));
        }
    }

    private void setContract(String sceneInstId, String custId, String rootOfferInstId, String offerId,
        String offerInstId) {
        List<KiteOfferInstContract> rootOfferInstContracts = querySceneInstService
            .listOfferInstContracts(custId, rootOfferInstId);
        if (KiteListUtils.isNotEmpty(rootOfferInstContracts)) {
            for (KiteOfferInstContract rootOfferInstContract : rootOfferInstContracts) {
                KiteOfferInstContract offerInstContract = KiteBeanUtils
                    .transform(rootOfferInstContract, KiteOfferInstContract.class);
                offerInstContract.setOfferInstId(offerInstId);
                offerInstContract.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                operateSceneInstService.addOfferInstContract(sceneInstId, offerInstContract, offerInstId,
                    RelType.OFFER_OBJ_REL_TYPE_190000, ActionType.A, KeyConsts.OFFER_CONTRACT_ROLE, offerId);
            }
        }
    }

    private void setBatchAdditionalPrice(String sceneInstId, String custId, String mainOfferId,
        String mainOfferInstId) {
        List<KiteOfferInst> curAdditionalOfferInsts =
            querySceneInstService.listAdditionalOfferInstsFromOfferInst(custId, mainOfferInstId);
        for (KiteOfferInst additionInst : curAdditionalOfferInsts) {
            // 标准月租
            KiteAttr priceAttr = additionInst.getAttr("200001354");
            if (Objects.isNull(priceAttr)) {
                return;
            }
            String additionOfferId = additionInst.getSpecId();
            Offer offerSpec = ProdFeeCache.get(additionOfferId);
            Map<String, Object> offerMap = offerSpec.getOfferMap();
            String discntCode = KiteMapUtils.getString(offerMap, "discntCode");
            Map<String, Object> goodsPrice =
                goodsPriceFactorService.getFeeProdPrice(sceneInstId, custId, mainOfferId, additionInst);
            if (Objects.isNull(goodsPrice)) {
                return;
            }
            List<Map<String, Object>> feeItemPrices = KiteMapUtils.getValue(goodsPrice, "feeItemPrice");
            if (Objects.isNull(feeItemPrices)) {
                return;
            }
            Map<String, Object> map = feeItemPrices.get(0);
            String price = KiteMapUtils.getString(map, "price");
            String feeCode = KiteMapUtils.getString(map, "feeCode");
            if (StringUtils.isNotEmpty(price) && KiteStringUtils.isEqual(feeCode, discntCode)) {
                priceAttr.setOriginValue(price);
                priceAttr.setDefaultValue("");
                priceAttr.setValue(price);
                priceAttr.setValueDesc(price);
            }
            operateSceneInstService.setAttr(sceneInstId, additionInst.getInstType(), additionInst.getOfferInstId(),
                priceAttr);
        }
    }

    /**
     * 保存实例化（保存修改）
     *
     * @param sceneInstId
     * @param detailId
     */
    @Override
    public Boolean saveModification(String sceneInstId, String batchId, String detailId) {
        String offerInstId = querySceneInstService.getExtParameterValue(sceneInstId, "curOfferInstId");
        // 将offerInstId写入表中
        Example example = new Example(KiteBatchAcceptDetail.class);
        example.createCriteria().andEqualTo("detailId", detailId).andEqualTo("batchId", batchId);
        kiteBatchAcceptDetailMapper.updateByExampleSelective(
            new KiteBatchAcceptDetail().setOfferInstId(Long.valueOf(offerInstId)), example);
        operateSceneInstService.removeExtParameter(sceneInstId, "curOfferInstId");
        return Boolean.TRUE;
    }

    /**
     * 取消实例化（取消修改）
     *
     * @param sceneInstId
     * @param custId
     * @return
     */
    @Override
    public Boolean cancelModification(String sceneInstId, String custId) {
        String batchId = querySceneInstService.getExtParameterValue(sceneInstId, "batchId");
        String offerInstId = querySceneInstService.getExtParameterValue(sceneInstId, "curOfferInstId");
        if (KiteStringUtils.isNotEmpty(offerInstId)) {
            KiteBatchAcceptDetail kiteBatchAcceptDetail = kiteBatchAcceptDetailMapper
                .selectOne(new KiteBatchAcceptDetail().setOfferInstId(Long.valueOf(offerInstId)).setBatchId(Long.valueOf(batchId)));
            // 第一条数据的实例不能删
            if (!Objects.isNull(kiteBatchAcceptDetail) && kiteBatchAcceptDetail.getLineNum() == 2) {
                return Boolean.TRUE;
            }
            // 实例ID没有入库的才删
            if (Objects.isNull(kiteBatchAcceptDetail)) {
                batchAcceptService.deleteOfferInstAndRelInsts(sceneInstId, custId, offerInstId);
                operateSceneInstService.removeExtParameter(sceneInstId, "curOfferInstId");
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 删除记录
     *
     * @param sceneInstId 场景实例标识
     * @param detailId    kiteBatchAcceptDetail记录的主键
     * @return
     */
    @Override
    public Boolean deleteRecord(String batchId, String sceneInstId, String custId, String detailId) {
        KiteBatchAcceptDetail kiteBatchAcceptDetail = kiteBatchAcceptDetailMapper
            .selectOne(new KiteBatchAcceptDetail().setDetailId(Long.valueOf(detailId)).setBatchId(Long.valueOf(batchId)));
        if (Objects.nonNull(kiteBatchAcceptDetail)) {
            Long offerInstId = kiteBatchAcceptDetail.getOfferInstId();
            if (offerInstId != null) {
                batchAcceptService.deleteOfferInstAndRelInsts(sceneInstId, custId, offerInstId.toString());
            }
            Example example = new Example(KiteBatchAcceptDetail.class);
            example.createCriteria().andEqualTo("detailId", detailId).andEqualTo("batchId", batchId);
            kiteBatchAcceptDetailMapper.updateByExampleSelective(
                new KiteBatchAcceptDetail().setStatusCd("1300").setStatusDate(LocalDateTime.now()), example);
            KiteBatchAccept kiteBatchAccept = kiteBatchAcceptMapper
                .selectByPrimaryKey(kiteBatchAcceptDetail.getBatchId());
            kiteBatchAccept.setImportNum(kiteBatchAccept.getImportNum() - 1);
            this.kiteBatchAcceptMapper.updateByPrimaryKey(kiteBatchAccept);
        }

        return Boolean.TRUE;
    }

    /**
     * 调整页面返回上传文件页面
     *
     * @param sceneInstId
     * @return
     */
    @Override public Boolean back2UploadPage(String sceneInstId) {
        operateSceneInstService.removeExtParameter(sceneInstId, "curOfferInstId");
        return operateSceneInstService.putExtParameter(sceneInstId, "nodeCode", "BatchInput");
    }

    @Override public DataResult<String> commitInstantiate(String sceneInstId, String batchId) {
        StopWatch stopWatch = new StopWatch("commitInstantiate");
        stopWatch.start("areYouReady");
        Map<String, Object> map = new HashMap<>();
        map.put("batchId", batchId);
        List<KiteBatchAcceptDetail> kiteBatchAcceptDetails = batchAcceptService.listDetial(map);
        // 提交前校验是否还存在校验失败的记录
        areYouReady(batchId, kiteBatchAcceptDetails);
        String checkResult = checkBeforeCommit(kiteBatchAcceptDetails, sceneInstId);
        if (KiteStringUtils.isNotEmpty(checkResult)) {
           return ErrorConsts.BUSI_COMMON_ERROR.getResult(checkResult, checkResult);
        }
        // 状态更新为提交处理中
        kiteBatchAcceptMapper.updateByPrimaryKeySelective(
            new KiteBatchAccept().setBatchId(Long.valueOf(batchId)).setStatusCd("1400")
                .setStatusDate(LocalDateTime.now()));
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        stopWatch.stop();
        CompletableFuture.runAsync(FunctionWrapper.wrapLoginInfoAndTrans(
            (Runnable) () -> this.operateShoppingCartService
                .toSettle(ContextUtil.getSimpleLoginInfo(), sceneInstId, null,
                    ContextUtil.getSimpleLoginInfo().getUserId().toString(), sceneInst.getCustId(),
                    KeyConsts.SHOPPING_CART_GROUP_STATUS_SETTLE)));

        System.out.println(stopWatch.prettyPrint());
        return ErrorConsts.SUCCESS.getResult("批次号:" + batchId);
    }

    private DataResult<String> commitScene(String sceneInstId, KiteBatchAcceptDetail kiteBatchAcceptDetail,
        CuccContextCustDTO contextCust) {

        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
        String staffId = sceneInst.getStaffId();
        String orgId = sceneInst.getOrgId();

        // 提交场景
        ISceneCommitService sceneCommitService = SpringUtil.getBean(ISceneCommitService.class);
        return sceneCommitService.batchAcceptCommit(sceneInstId, staffId, orgId, contextCust,
            kiteBatchAcceptDetail.getOfferInstId().toString());
    }

    private void areYouReady(String batchId, List<KiteBatchAcceptDetail> kiteBatchAcceptDetails) {
        KiteBatchAccept kiteBatchAccept = kiteBatchAcceptMapper.selectByPrimaryKey(batchId);
        KiteAssert.notNull(kiteBatchAccept, ErrorConsts.BUSI_COMMON_ERROR, "导入文件记录不存在");

        if (KiteStringUtils.equalsAny(kiteBatchAccept.getImportType(), LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_4000,
            LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_5000)) {
            List<KiteBatchAcceptDetail> failDetails = kiteBatchAcceptDetails.stream()
                .filter(detail -> KiteStringUtils.equals(detail.getCheckStatus(), "1100")).collect(Collectors.toList());
            KiteAssert.empty(failDetails, ErrorConsts.BUSI_COMMON_ERROR, "还存在校验失败的记录，不允许提交");
        }
    }

    private String checkBeforeCommit(List<KiteBatchAcceptDetail> kiteBatchAcceptDetails, String sceneInstId) {
        // 数据库配置了的省份才生效
        if (GeneralSwitchUtils.isSwitchClosed("BATCH_COMMIT_CHECK_ADDRESS")) {
            return null;
        }
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(sceneInstId);
        String provinceStr = DcPublicCache.getPCode("2021092801","PROVINCE_TYPE");
        if (!KiteStringUtils.contains(provinceStr, kiteSceneInst.getProvinceNbr())) {
            return null;
        }
        // 未实例化的实例化到场景中
        ExecutorService executorService = null;
        List<Callable<Boolean>> tasks = new ArrayList<>();
        StringBuffer result = new StringBuffer();
        List<KiteProdInst> prodInsts = querySceneInstService.listProdInsts(sceneInstId);

        kiteBatchAcceptDetails.forEach(kiteBatchAcceptDetail -> {
            try {
                if (Objects.isNull(kiteBatchAcceptDetail.getOfferInstId())) {
                    result.append("第").append(kiteBatchAcceptDetail.getLineNum() - 1)
                        .append("条记录必须录入8级以上标准地址，请点击【修改】按钮进行修改");
                    return;
                }
                KiteProdInst prodInst = prodInsts.stream().filter(prodInstDTO  -> {
                    KiteOfferInst mainOfferInst = Optional.ofNullable(querySceneInstService
                            .getMainOfferInstByProdInstId(kiteSceneInst.getCustId(), prodInstDTO.getProdInstId()))
                        .orElse(new KiteOfferInst());
                    return KiteStringUtils.isEqual(mainOfferInst.getOfferInstId(),
                        kiteBatchAcceptDetail.getOfferInstId().toString());
                }).findFirst().orElse(null);
                if (Objects.isNull(prodInst)) {
                    result.append("第").append(kiteBatchAcceptDetail.getLineNum() - 1)
                        .append("条记录必须录入8级以上标准地址，请点击【修改】按钮进行修改;");
                    return;
                }
                KiteAttr addressId = prodInst.getAttr("200002617"); // 互联网专线
                if (Objects.nonNull(addressId) && KiteStringUtils.isEmpty(addressId.getValue())) {
                    result.append("第").append(kiteBatchAcceptDetail.getLineNum() - 1)
                        .append("装机地址必须录入8级以上标准地址，请点击【修改】按钮进行修改;");
                }
                KiteAttr aAddressId = prodInst.getAttr("200002618");
                if (Objects.nonNull(aAddressId) && KiteStringUtils.isEmpty(aAddressId.getValue())) {
                    result.append("第").append(kiteBatchAcceptDetail.getLineNum() - 1)
                        .append("条记录的A端装机地址必须录入8级以上标准地址，请点击【修改】按钮进行修改;");
                }
                KiteAttr zAddressId = prodInst.getAttr("200002619");
                if (Objects.nonNull(zAddressId) && KiteStringUtils.isEmpty(zAddressId.getValue())) {
                    result.append("第").append(kiteBatchAcceptDetail.getLineNum() - 1)
                        .append("条记录的Z端装机地址必须录入8级以上标准地址，请点击【修改】按钮进行修改;");
                }
            } catch (Exception e) {
                result.append("第").append(kiteBatchAcceptDetail.getLineNum() - 1).append("条记录").append(e.getMessage()).append(";");
            }
        });

        return result.toString();
    }

    /**
     * 重提
     *
     * @param batchId
     * @return
     */
    @Override public Boolean recommit(String batchId) {
        KiteBatchAccept kiteBatchAccept = kiteBatchAcceptMapper.selectByPrimaryKey(batchId);
        KiteAssert.notNull(kiteBatchAccept, ErrorConsts.BUSI_COMMON_ERROR, "该批次记录不存在：" + batchId);

        // 定时任务正在处理，不允许重提
        Example example = new Example(KiteBatchAcceptDetail.class);
        example.createCriteria().andEqualTo("batchId", batchId)
                .andIsNotNull("randomNum").andEqualTo("statusCd", LocalKeyConsts.COLLECTION_GROUP_DEAL_STATUS_CD_1000);
        List<KiteBatchAcceptDetail> detailList = kiteBatchAcceptDetailMapper.selectByExample(example);
        if (!KiteListUtils.isEmpty(detailList)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("该批次数据处理中，不能重提");
        }
        example.clear();
        example.createCriteria().andEqualTo("batchId", batchId)
            .andNotEqualTo("statusCd", LocalKeyConsts.COLLECTION_GROUP_DEAL_STATUS_CD_1200);
        detailList = kiteBatchAcceptDetailMapper.selectByExample(example);

        // 直接更新状态、随机数
        List<Long> detailIds = detailList.stream().map(KiteBatchAcceptDetail::getDetailId).collect(Collectors.toList());
        kiteBatchAcceptDetailMapper.recommitUpdate(detailIds, batchId);
        // 更新批次状态为更新中
        kiteBatchAcceptMapper.updateByPrimaryKeySelective(kiteBatchAccept.setStatusCd("1400").setStatusDate(LocalDateTime.now()));

        LoginInfo loginInfo = ContextUtil.getLoginInfo();
        Map<String, Object> extParams = loginInfo.getUserInfo().getExtParams();
        extParams.put("KITE_SCENEINST_CARTID", kiteBatchAccept.getCartId().toString());
        ContextUtil.setLoginInfo(loginInfo);
        // 记录重提
        KiteSceneInst kiteSceneInst = this.querySceneInstService
            .getSceneInst(kiteBatchAccept.getSceneInstId().toString(), kiteBatchAccept.getCustId().toString());
        this.operateSceneInstService.putExtParameter(kiteBatchAccept.getSceneInstId().toString(), "failRecommit", "T");
        this.operateSceneInstService.putExtParameter(kiteBatchAccept.getSceneInstId().toString(), "failRecommitRoot",
                detailList.stream().anyMatch(detail -> (detail.getOfferInstId() != null && KiteStringUtils.equals(detail.getOfferInstId().toString(), kiteSceneInst.getRootInstId()))));
        return Boolean.TRUE;
    }

    @Override
    public Boolean commitJob() {
        List<Map<String, Object>> batchList = kiteBatchAcceptMapper.listBatchAcceptBatchIds(Lists
            .newArrayList(LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_4000, LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_5000));
        /*List<String> batchIds = kiteBatchAcceptDetailMapper.listCommitBatchId(Lists
                .newArrayList(LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_4000, LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_5000),
            BatchAcceptStatusEnum.STATUS_CD_1400.getStatusCd(), BatchAcceptStatusEnum.CHECK_STATUS_1200.getStatusCd(),
            StatusConst.NOT_STATUSCD);*/

        if (KiteListUtils.isEmpty(batchList)) {
            return Boolean.TRUE;
        }

        String curBatchId = null;
        List<KiteBatchAcceptDetailDTO> detailDTOList = null;
        String num = DcSystemParamCache.getDcParamVal("BATCH_ACCEPT_JOB_NUM");
        if (KiteStringUtils.isEmpty(num)) {
            num = "40";
        }
        // 找出要处理的批次
        for (Map<String, Object> batch : batchList) {
            String batchId = KiteMapUtils.getString(batch, "batch_id");
            // 拿到批数据的新的随机数，并且更新到批数据中
            // 取数据时要控制事务，取完的数据不允许其它程序再取了
            String tempRandom = BatchAcceptUtil.createRandom();
            try {
                String finalNum = num;
                TransactionUtils.executeNew(
                    () -> kiteBatchAcceptDetailMapper.updateRandom(tempRandom, batchId, Integer.parseInt(finalNum),
                        BatchAcceptStatusEnum.CHECK_STATUS_1200.getStatusCd()));
            }
            catch (Exception e) {
                LOGGER.error("commitJob-->", e, e.getMessage());
                ErrorConsts.BUSI_COMMON_ERROR.throwOut("更新随机数失败");
            }
            detailDTOList = kiteBatchAcceptDetailMapper.listExecuteDetails(batchId, tempRandom);
            //拿到需要处理的数据就中止循环
            if (!KiteListUtils.isEmpty(detailDTOList)) {
                curBatchId = batchId;
                break;
            }
        }

        Map<String, LoginInfo> loginInfoMap = new HashMap<>();
        Map<String, CuccContextCustDTO> custInfoMap = new HashMap<>();
        ICustReceptionService custReceptionService = SpringUtil.getBean(ICustReceptionService.class);
        StopWatch stopWatch = new StopWatch("commit");
        stopWatch.start("commitScene");

        if (KiteListUtils.isEmpty(detailDTOList)) {
            return Boolean.TRUE;
        }

        // 判断逐条转单还是统一转单
        if (GeneralSwitchUtils.isSwitchClosed("IS_BATCH_JOB_COMMIT_SINGLE")) {
            List<KiteBatchAcceptDetailDTO> finalDetailDTOList = detailDTOList;
            List<KiteBatchAcceptDetailDTO> finalDetailDTOList1 = detailDTOList;
            CompletableFuture.runAsync(() -> {
                commitAllJob(finalDetailDTOList, finalDetailDTOList1.get(0).getSceneInstId());
            });
            return Boolean.TRUE;
        }

        detailDTOList.forEach(detailDTO -> {
            AtomicReference<DataResult<String>> result = new AtomicReference<>(new DataResult<>());
            Example example = new Example(KiteBatchAcceptDetail.class);
            example.createCriteria().andEqualTo("detailId", detailDTO.getDetailId())
                .andEqualTo("batchId", detailDTO.getBatchId());
            try {
                LoginInfo loginInfo = KiteMapUtils.getValue(loginInfoMap, detailDTO.getCreateStaff().toString());
                if (Objects.isNull(loginInfo)) {
                    loginInfo = BatchAcceptUtil.getLoginInfo(detailDTO);
                    loginInfoMap.put(detailDTO.getCreateStaff().toString(), loginInfo);
                }
                ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
                // 查客户详情（为了避免多次调接口，同一个客户根据客户id用map保存）
                CuccContextCustDTO contextCust = custInfoMap.get(detailDTO.getCustId());
                if (Objects.isNull(contextCust)) {
                    contextCust = new CuccContextCustDTO();
                    AtomicReference<CuccCustInfoDetailDTO> custInfoAtomic = new AtomicReference<>(null);
                    custInfoAtomic.set(custReceptionService.getCustomerInfoNew(detailDTO.getCustId()));

                    if (Objects.nonNull(custInfoAtomic.get())) {
                        CuccCustInfoDetailDTO cuccCustInfoDTO = custInfoAtomic.get();
                        KiteBeanUtils.copyProperties(cuccCustInfoDTO, contextCust);
                        contextCust.setLanId(cuccCustInfoDTO.getCityCode());
                        contextCust.setRegionId(cuccCustInfoDTO.getBcityCode());
                        contextCust.setCustType(cuccCustInfoDTO.getCustClassType());
                        contextCust.setCbssId(cuccCustInfoDTO.getCustId());
                    }
                    custInfoMap.put(detailDTO.getCustId(), contextCust);
                }
                CustDTO custDTO = packageCustDTO(contextCust);
                // 如果销售品实例id为空，则认为没有实例化，实例化后再转单
                if (Objects.isNull(detailDTO.getOfferInstId())) {
                    StopWatch stopWatchInst = new StopWatch("instantiate");
                    stopWatchInst.start("instantiate");
                    String offerInstId = instantiate(detailDTO.getSceneInstId(), detailDTO, contextCust, custDTO);
                    //                    String offerInstId = querySceneInstService.getExtParameterValue(detailDTO.getSceneInstId(), "curOfferInstId");
                    detailDTO.setOfferInstId(Long.parseLong(offerInstId));
                    TransactionUtils.executeNew(() -> {
                        kiteBatchAcceptDetailMapper.updateByExampleSelective(
                            new KiteBatchAcceptDetail().setOfferInstId(detailDTO.getOfferInstId()), example);
                    });
                    stopWatchInst.stop();
                    System.out.println(stopWatchInst.prettyPrint());
                }
                if (Objects.nonNull(detailDTO.getOfferInstId())) {
                    // 提交场景
                    result.set(commitScene(detailDTO.getSceneInstId(), detailDTO, contextCust));
                }
                else {
                    // 失败
                    result.get().setResultCode("9999");
                    result.get().setResultObject("实例化失败");
                }
            }
            catch (Exception e) {
                System.out.println("批量受理异常捕获：");
                LOGGER.error("批量受理异常捕获-->", e, e.getMessage());
                result.get().setResultObject(ExceptionUtils.getStackTrace(e));
            }
            finally {
                System.out.println("批量受理更新处理结果：");
                LocalDateTime now = LocalDateTime.now();
                TransactionUtils.executeNew(() -> {
                    if (KiteStringUtils.isEqual(ErrorConsts.SUCCESS.getCode(), result.get().getResultCode())) {
                        // 成功
                        KiteBatchAcceptDetail detail = new KiteBatchAcceptDetail()
                            .setExtOrderId(result.get().getResultObject()).setDealResult("批量处理成功，订单号："+result.get().getResultObject())
                            .setStatusCd("1200").setStatusDate(now);
                        detailDTO.setStatusCd("1200");
                        kiteBatchAcceptDetailMapper.updateByExampleSelective(detail, example);
                    }
                    else {
                        // 失败
                        KiteBatchAcceptDetail detail = new KiteBatchAcceptDetail()
                            .setDealResult(result.get().getResultObject()).setStatusCd("1100").setStatusDate(now);
                        detailDTO.setStatusCd("1100");
                        kiteBatchAcceptDetailMapper.updateByExampleSelective(detail, example);
                    }
                });
                ContextUtil.removeThreadLocal();
            }
        });

        updateBatchStatus(curBatchId);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        return Boolean.TRUE;
    }

    /**
     * 更新批次表状态，如果一个批次有一条失败了，则认为批次处理失败
     *
     * @param batchId
     */
    private void updateBatchStatus(String batchId) {
        System.out.println("批量受理批次状态：");
        if (KiteStringUtils.isEmpty(batchId)) {
            return;
        }
        TransactionUtils.executeNew(() -> {
            List<KiteBatchAcceptDetail> details = kiteBatchAcceptDetailMapper
                .select(new KiteBatchAcceptDetail().setBatchId(Long.valueOf(batchId)));
            if (details.stream().noneMatch(detail -> KiteStringUtils.equals(detail.getStatusCd(), "1000"))) {
                if (details.stream().anyMatch(detail -> !KiteStringUtils.equals(detail.getStatusCd(), "1200"))) {
                    kiteBatchAcceptMapper.updateByPrimaryKeySelective(
                        new KiteBatchAccept().setBatchId(Long.valueOf(batchId)).setStatusCd("1600")
                            .setStatusDate(LocalDateTime.now()));
                }
                else {
                    kiteBatchAcceptMapper.updateByPrimaryKeySelective(
                        new KiteBatchAccept().setBatchId(Long.valueOf(batchId)).setStatusCd("1500")
                            .setStatusDate(LocalDateTime.now()));
                    // 所有记录都成功后归档购物车
                    KiteBatchAccept batchAccept = kiteBatchAcceptMapper
                        .selectByPrimaryKey(new KiteBatchAccept().setBatchId(Long.parseLong(batchId)));
                    SpringUtil.getBean(ISceneCommitService.class)
                        .archiveData(batchAccept.getSceneInstId().toString(), batchAccept.getCreateStaff().toString(),
                            batchAccept.getCreateOrgId(), batchAccept.getCustId().toString());
                }
            }
        });

    }

    private Boolean commitAllJob(List<KiteBatchAcceptDetailDTO> detailDTOS, String sceneInstId) {
        if (KiteListUtils.isEmpty(detailDTOS)) {
            return Boolean.TRUE;
        }
        AtomicReference<DataResult<String>> result = new AtomicReference<>(new DataResult<>());
        List<KiteBatchAcceptDetailDTO> kiteBatchAcceptDetails = Collections.synchronizedList(
            detailDTOS.stream().filter(kiteBatchAcceptDetail -> kiteBatchAcceptDetail.getOfferInstId() != null)
                .collect(Collectors.toList()));
        try {
            KiteTransactionUtils.beginTransaction();
            if (KiteStringUtils.isBlank(KiteTransactionUtils.getTransactionId())) {
                String transactionId = KiteTransactionUtils.genTransactionId();
                System.out.println("genTransactionId:" + transactionId);
                KiteTransactionUtils.setTransactionId(transactionId);
            }
            LoginInfo loginInfo = BatchAcceptUtil.getLoginInfo(detailDTOS.get(0));
            ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
            String custId = detailDTOS.get(0).getCustId();
            // 查客户，提交场景需要
            CuccContextCustDTO contextCust = new CuccContextCustDTO();
            ICustReceptionService custReceptionService = SpringUtil.getBean(ICustReceptionService.class);
            CuccCustInfoDetailDTO cuccCustInfoDTO = custReceptionService
                .getCustomerInfoNew(custId);
            if (Objects.nonNull(cuccCustInfoDTO)) {
                KiteBeanUtils.copyProperties(cuccCustInfoDTO, contextCust);
                contextCust.setLanId(cuccCustInfoDTO.getCityCode());
                contextCust.setRegionId(cuccCustInfoDTO.getBcityCode());
                contextCust.setCustType(cuccCustInfoDTO.getCustClassType());
                contextCust.setCbssId(cuccCustInfoDTO.getCustId());
            }
            CustDTO custDTO = packageCustDTO(contextCust);
            // 重新加载一次场景到缓存中（防止缓存过去，多线程中每个线程都还原）
            querySceneInstService.getSceneInst(sceneInstId, custId);
            StopWatch stopWatch = new StopWatch("commitAllJob");
            stopWatch.start("instantiate");

            List<Callable<Boolean>> tasks = new ArrayList<>();
            long start = System.currentTimeMillis();
            System.out.println("job start==>" + start);

            List<KiteBatchAcceptDetailDTO> collect = detailDTOS.stream()
                .filter(kiteBatchAcceptDetail -> kiteBatchAcceptDetail.getOfferInstId() == null).collect(Collectors.toList());
            collect.forEach(kiteBatchAcceptDetail -> {
                String offerInstId = instantiate2(sceneInstId, kiteBatchAcceptDetail, contextCust, custDTO);
                kiteBatchAcceptDetail.setOfferInstId(Long.parseLong(offerInstId));

                KiteSceneInst sceneInst = null;
                if (Objects.nonNull(contextCust)) {
                    sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
                } else {
                    sceneInst = querySceneInstService.getSceneInst(sceneInstId);
                }
                String custId2 = sceneInst.getCustId();
                KiteOfferInst rootOfferInst = querySceneInstService.getOfferInst(custId, sceneInst.getRootInstId());
                String rootOfferInstId = rootOfferInst.getOfferInstId();
                String offerId = rootOfferInst.getOfferId();
                // 设置合同信息
                setContract(sceneInstId, custId2, rootOfferInstId, offerId, offerInstId);
                // 设置折扣信息
                setDiscount(sceneInstId, custId2, rootOfferInstId, offerInstId);
                // 设置付费关系
                setAccount(sceneInstId, custId2, rootOfferInstId, offerId, offerInstId);
                // 设置可选包
                setAdditionalOfferInst(sceneInstId, custId2, rootOfferInstId, offerInstId);
            });
            System.out.println("job instantiate2==>" + (System.currentTimeMillis() - start));
            KiteTransactionUtils.commit();
            KiteTransactionUtils.beginTransaction();

            collect.forEach(kiteBatchAcceptDetail -> {
                tasks.add(FunctionWrapper.wrapLoginInfoAndTrans(() -> {
                    String offerInstId = String.valueOf(kiteBatchAcceptDetail.getOfferInstId());
                    try {
                        operateSceneInstService.putExtParameter(sceneInstId, "curOfferInstId", offerInstId);
                        ServiceContext.setCurOfferInstId(offerInstId);
                        ServiceContext.setIsBatchAccept(Boolean.TRUE);
                        KiteSceneInst sceneInst = null;
                        if (Objects.nonNull(contextCust)) {
                            sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
                        } else {
                            sceneInst = querySceneInstService.getSceneInst(sceneInstId);
                        }
                        List<KiteProdInst> kiteProdInsts =
                            querySceneInstService.listProdInstsFromOfferInst(custId, offerInstId);
                        operateSceneBO.executeBatchAcceptAttrAfter(custId, sceneInst, custDTO, kiteProdInsts.get(0));
                        String custId2 = sceneInst.getCustId();
                        KiteOfferInst rootOfferInst =
                            querySceneInstService.getOfferInst(custId, sceneInst.getRootInstId());
                        String offerId = rootOfferInst.getOfferId();

                        // 设置销售品属性
                        setOfferAttr(sceneInstId, custId2, rootOfferInst, offerInstId);
                        // 设置产品属性
                        localBatchAcceptBO.setProdAttr(sceneInstId,
                            Objects.requireNonNull(
                                JSONObject.parseArray(kiteBatchAcceptDetail.getAttrJson(), KiteAttr.class)),
                            custId2, offerInstId, contextCust);

                        // 重新设置kiteAttr.instId
                        List<KiteProdInst> newKiteProdInsts =
                            querySceneInstService.listProdInstsFromOfferInst(custId2, offerInstId);
                        for (KiteProdInst kiteProdInst : newKiteProdInsts) {
                            operateSceneInstService.replaceAttrs(sceneInstId, kiteProdInst.getInstType(),
                                kiteProdInst.getProdInstId(), kiteProdInst.listAttrs());
                        }
                        // 设置完属性后，调资费计价接口
                        setBatchAdditionalPrice(sceneInstId, custId2, offerId, offerInstId);
                        return Boolean.TRUE;
                    } catch (Exception e) {
                        kiteBatchAcceptDetail.setStatusCd("1100");
                        kiteBatchAcceptDetail.setDealResult(ExceptionUtils.getStackTrace(e));
                        if (KiteStringUtils.isNotEmpty(offerInstId)) {
                            batchAcceptService.deleteOfferInstAndRelInsts(sceneInstId, custId, offerInstId);
                        }
                        return Boolean.FALSE;
                    } finally {
                        kiteBatchAcceptDetails.add(kiteBatchAcceptDetail);
                        ServiceContext.remove();
                    }
                }));
            });

            try {
                ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("instantiate-thread-pool-%d")
                    .build();
                executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
                    Runtime.getRuntime().availableProcessors(), 5000L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(300), threadFactory);
                executorService.invokeAll(tasks);
            }
            catch (InterruptedException e) {
                System.out.println(e.getCause());
                ErrorConsts.BUSI_COMMON_ERROR.throwOut(e, "初始化失败");
            }
            finally {
                if (Objects.nonNull(executorService)) {
                    executorService.shutdown();
                }
            }
            KiteTransactionUtils.commit();

            stopWatch.stop();
            System.out.println(stopWatch.prettyPrint());
            stopWatch.start("commit");
            KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
            String staffId = sceneInst.getStaffId();
            String orgId = sceneInst.getOrgId();

            System.out.println("job thread run==>" + (System.currentTimeMillis() - start));

            String failRecommit = this.querySceneInstService.getExtParameterValue(sceneInstId, "failRecommit");
            if (KiteStringUtils.equals(failRecommit, KeyConsts.IFTRUE_T)) {
                List<KiteBatchAcceptDetailDTO> executeDetails = kiteBatchAcceptDetails.stream()
                    .filter(detailDTO -> !KiteStringUtils.equals(detailDTO.getStatusCd(), "1100"))
                    .collect(Collectors.toList());
                operateSceneInstService.putExtParameter(sceneInstId, "executeDetails", executeDetails);
            }

            // 提交场景
            ISceneCommitService sceneCommitService = SpringUtil.getBean(ISceneCommitService.class);
            TransactionUtils.executeNew(
                () -> {
                    result.set(sceneCommitService.commitScene(sceneInstId, staffId, orgId, contextCust, false, false));
                });
            stopWatch.stop();
            System.out.println("job commitScene==>" + (System.currentTimeMillis() - start));
            System.out.println(stopWatch.prettyPrint());
        }
        catch (Exception e) {
            System.out.println("批量受理异常捕获：");
            LOGGER.error(e);
            result.get().setResultObject(ExceptionUtils.getStackTrace(e));
        }
        finally {
            System.out.println("1批量受理更新处理结果：");
            LocalDateTime now = LocalDateTime.now();
            DataResult<String> finalResult = result.get();
            TransactionUtils.executeNew(() -> {
                List<KiteBatchAcceptDetail> kiteBatchAcceptDetailList = new ArrayList<>();
                try {
                    if (KiteStringUtils.isEqual(ErrorConsts.SUCCESS.getCode(), finalResult.getResultCode())) {
                        // 成功
                        kiteBatchAcceptDetails.forEach(detailDTO -> {
                            KiteBatchAcceptDetail detail = new KiteBatchAcceptDetail().setStatusDate(now);
                            detail.setBatchId(detailDTO.getBatchId())
                                .setDetailId(detailDTO.getDetailId());
                            if (KiteStringUtils.equals(detailDTO.getStatusCd(), "1100")) {
                                detail.setStatusCd(detailDTO.getStatusCd()).setDealResult(detailDTO.getDealResult());
                            }
                            else {
                                detail.setExtOrderId(finalResult.getResultObject())
                                    .setDealResult("批量处理成功，订单号：" + finalResult.getResultObject()).setStatusCd("1200")
                                    .setOfferInstId(detailDTO.getOfferInstId());
                            }
                            kiteBatchAcceptDetailList.add(detail);
                        });
                    }
                    else {
                        // 失败
                        // 全部失败，每条数据都要更新
                        detailDTOS.forEach(detailDTO -> {
                            KiteBatchAcceptDetail detail = new KiteBatchAcceptDetail()
                                .setDealResult(finalResult.getResultObject()).setStatusCd("1100").setStatusDate(now);
                            detail.setStatusCd("1100");
                            detail.setBatchId(detailDTO.getBatchId())
                                .setDetailId(detailDTO.getDetailId());
                            kiteBatchAcceptDetailList.add(detail);
                        });
                    }
                    final long start2 = System.currentTimeMillis();
                    kiteBatchAcceptDetailMapper.updateKiteBatchAcceptDetailStatusAndOrderId(kiteBatchAcceptDetailList);
                    kiteBatchAcceptMapper.updateByPrimaryKeySelective(
                        new KiteBatchAccept().setBatchId(kiteBatchAcceptDetailList.get(0).getBatchId())
                            .setStatusCd(BatchAcceptStatusEnum.STATUS_CD_1500.getStatusCd()));
                    System.out.println("job update==>" + (System.currentTimeMillis() - start2));
                }
                catch (Exception e) {
                    LOGGER.error(e);
                }
            });
            ContextUtil.removeThreadLocal();
        }

        return Boolean.TRUE;
    }
}
